﻿// (c)2010 David Schwarz (david.schwarz@live.com)
// This file is licensed under GNU GPL v2 license, see more at http://www.gnu.org/licenses/gpl-2.0.html
namespace Z2.Core
{

	#region Using

	using System;
	using Microsoft.Xna.Framework;
	using System.Diagnostics;
	using System.Collections.Generic;

	#endregion

	public delegate bool CanCollideDelegate(ObjectBase thisObj, ObjectBase obj);

	/// <summary>
	/// Třída definující standrdní chování objektu (působící gravitace)
	/// </summary>
	internal class GravityBehavior : ObjectBehaviorBase
	{

		#region Const

		private const float GRAVITY_MAX = 10.0f;
		private const float GRAVITY_DEFAULT = 0.1f;
		private const float GRAVITY_BOOST = 0.5f;

		#endregion

		#region Constructor

		/// <summary>
		/// Konstruktor
		/// </summary>
		public GravityBehavior()
			: base()
		{
		}

		#endregion

		#region Override Methods

		private bool CantCollide(ObjectBase thisObj, ObjectBase obj)
		{
			return obj == thisObj || obj is ParticleBasic || thisObj.CantCollide(obj);
		}

		/// <summary>
		/// Metoda, která modifikuje vektor pohybu objektu <paramref name="obj"/>
		/// </summary>
		/// <param name="obj"><see cref="ObjectBase"/></param>
		internal override void ModifyVector(ObjectBase obj)
		{
			// Změna vektoru v ose X & Ošetření maximální rychlosti v ose X
			if (obj.Change.X != 0)
			{
				obj.Move = new Vector2(obj.Move.X + obj.Change.X, obj.Move.Y);
				if (obj.MaxHorizontalSpeed > 0 && Math.Abs(obj.Move.X) > obj.MaxHorizontalSpeed)
				{
					obj.Move = new Vector2(obj.Move.X > 0 ? obj.MaxHorizontalSpeed : -obj.MaxHorizontalSpeed, obj.Move.Y);
				}
			}

			if (obj.IsInWater) obj.Move = new Vector2(obj.Move.X / 1.5F, obj.Move.Y / 1.3F);

			Rectangle rect;
			IntersectionResult ir;
			List<ObjectBase> objects = World.Current.GetSectorsObjects(obj, CantCollide);

			bool cwo = false;

			// Check for gravity
			rect = obj.GetRectangle(0, obj.Move.Y + GravityBehavior.GRAVITY_BOOST);

			ir = World.Current.Intersects(obj, rect, true);
			cwo = ir.IsCollision;
			foreach (ObjectBase objBase in objects)
			{
				if (CantCollide(obj, objBase)) continue;

				ir = obj.Intersects(objBase, rect);
				if (ir.IsCollision)
				{
					cwo = true;
				}
			}

			if (cwo)
			{
				if (obj.Move.Y > 0)
				{
					obj.VerticalState = ObjectStateVertical.Idle;
					obj.OnVerticalCollision(ir);
				}
				obj.Move = new Vector2(obj.Move.X, 0);
			}
			else
			{
				obj.Link = Vector2.Zero;
				obj.Move = new Vector2(obj.Move.X, obj.Move.Y + GravityBehavior.GRAVITY_BOOST);
				obj.VerticalState = ObjectStateVertical.Falling;
			}

			// Horizontal
			rect = obj.GetRectangle(obj.Move.X + obj.Link.X, 0);

			ir = World.Current.Intersects(obj, rect, false);
			cwo = ir.IsCollision;
			
			foreach (ObjectBase objBase in objects)
			{
				if (CantCollide(obj, objBase)) continue;

				ir = obj.Intersects(objBase, rect);
				if (ir.IsCollision)
				{
					cwo = true;
					objBase.ChangeHorizontal(obj.Move.X);
				}
			}

			if (cwo)
			{
				obj.Move = new Vector2(0, obj.Move.Y);
			}
			else
			{
				obj.Position = new Vector2(obj.Position.X + obj.Move.X + obj.Link.X, obj.Position.Y);
			}

			cwo = false;
			
			// Vertical
			rect = obj.GetRectangle(0, obj.Move.Y);

			ir = World.Current.Intersects(obj, rect, true);
			cwo = ir.IsCollision;

			foreach (ObjectBase objBase in objects)
			{
				if (CantCollide(obj, objBase)) continue;

				ir = obj.Intersects(objBase, rect);
				if (ir.IsCollision)
				{
					cwo = true;
				}
			}

			// if there's a correction in vertical dir. set, disable collision
			if (cwo && obj.CorrectPosition.Y != 0) cwo = false;

			if (cwo)
			{
				if (obj.VerticalState != ObjectStateVertical.Idle)
				{
					obj.VerticalState = ObjectStateVertical.Idle;
					//obj.OnVerticalCollision(ir);
				}
				obj.Move = new Vector2(obj.Move.X, 0);
			}
			else
			{
				obj.Link = Vector2.Zero;
				

				if (!obj.IsStatic && obj.CorrectPosition != Vector2.Zero)
				{
					float add = (obj.CorrectPosition.Y - obj.Position.Y) / 1.5f;
					obj.Position = new Vector2(obj.Position.X, obj.Position.Y + add);
					if (Convert.ToInt32(add) == 0) obj.CorrectPosition = Vector2.Zero;
				}
				else
				{
					obj.Position = new Vector2(obj.Position.X, obj.Position.Y + obj.Move.Y);
				}

				if (obj.Move.Y != 0)
				{
					obj.VerticalState = obj.Move.Y > 0 ? ObjectStateVertical.Falling : ObjectStateVertical.Rising;
				}
			}
		}



		#endregion

	}
}
